package tjs.styudy.mini.springboot.transaction.config;

import org.springframework.beans.factory.ObjectProvider;
import tjs.styudy.mini.springboot.transaction.aop.MiniTransactional;
import tjs.styudy.mini.springboot.transaction.aop.Propagation;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

/**
 * Created by Nicky.Tang on 2021/10/27 4:34 下午
 *
 * @since 02.12.10
 */
public class TransactionManager {
    private DataSource dataSource;

    public TransactionManager(ObjectProvider<DataSource> dataSourceProvider) {
        this.dataSource = dataSourceProvider.getIfAvailable();
    }

    public TransactionInfo createTransactionIfNecessary(MiniTransactional miniTransactional) {
        TransactionInfo transactionInfo = new TransactionInfo();
        boolean needNew = false;
        if (miniTransactional != null && miniTransactional.propagation() == Propagation.REQUIRES_NEW) {
            needNew = true;
        }

        // 获取连接（可能会调用setAutoCommit）
        ConnectionHolder curConnectionHolder = transactionInfo.createConnectionIfNecessary(this.dataSource, needNew);
        transactionInfo.setConnection(curConnectionHolder.getCurConnection());

        // 绑定ThreadLocal
        ConnectionHolder.bindResource(curConnectionHolder);
        return transactionInfo;
    }

    public void rollBack(TransactionInfo transactionInfo) throws SQLException {
        try {
            if (transactionInfo.isNewTransaction()) {
                // 执行回滚事务
                transactionInfo.getConnection().rollback();
            }
        } finally {
            // 清理资源
            TransactionManager.cleanupAfterCompletion();
        }
    }

    public void commit(TransactionInfo transactionInfo) throws SQLException {
        try {
            if (transactionInfo.isNewTransaction()) {
                // 执行提交事务
                transactionInfo.getConnection().commit();
            }
        } finally {
            // 清理资源
            TransactionManager.cleanupAfterCompletion();
        }
    }

    public static void cleanupAfterCompletion() {
        // 先将当前连接还回连接池
        Connection curConnection = ConnectionHolder.getCurConnectionStatic();
        if(curConnection!=null){
            try {
                curConnection.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }

        // 再重置当前连接为上一个方法的连接
        ConnectionHolder.unbindResource();
    }
}
